package com.talkweb.osmharmony.tileprovider.modules;

import com.talkweb.osmharmony.config.Configuration;
import com.talkweb.osmharmony.tileprovider.IRegisterReceiver;
import com.talkweb.osmharmony.tileprovider.constants.OpenStreetMapTileProviderConstants;
import com.talkweb.osmharmony.tileprovider.tilesource.PixelMapTileSourceBase.LowMemoryException;
import com.talkweb.osmharmony.tileprovider.tilesource.ITileSource;
import com.talkweb.osmharmony.tileprovider.tilesource.TileSourceFactory;
import ohos.agp.components.element.Element;
import ohos.global.resource.ResourceManager;

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Implements a file system cache and provides cached tiles from Assets. This
 * functions as a tile provider by serving cached tiles for the supplied tile
 * source.
 * <p>
 * tiles should be put into apk's assets directory just like following example:
 * <p>
 * assets/Mapnik/11/1316/806.png
 *
 * @author Marc Kurtz
 * @author Nicolas Gramlich
 * @author Behrooz Shabani (everplays)
 */
public class MapTileAssetsProvider extends MapTileFileStorageProviderBase {

    // ===========================================================
    // Constants
    // ===========================================================

    // ===========================================================
    // Fields
    // ===========================================================

    private final ResourceManager mAssets;

    private final AtomicReference<ITileSource> mTileSource = new AtomicReference<ITileSource>();

    // ===========================================================
    // Constructors
    // ===========================================================

    public MapTileAssetsProvider(final IRegisterReceiver pRegisterReceiver, final ResourceManager pAssets) {
        this(pRegisterReceiver, pAssets, TileSourceFactory.DEFAULT_TILE_SOURCE);
    }

    public MapTileAssetsProvider(final IRegisterReceiver pRegisterReceiver,
                                 final ResourceManager pRawFile,
                                 final ITileSource pTileSource) {
        this(pRegisterReceiver, pRawFile, pTileSource,
                Configuration.getInstance().getTileDownloadThreads(),
                Configuration.getInstance().getTileDownloadMaxQueueSize()
        );
    }

    public MapTileAssetsProvider(final IRegisterReceiver pRegisterReceiver,
                                 final ResourceManager pAssets,
                                 final ITileSource pTileSource, int pThreadPoolSize,
                                 int pPendingQueueSize) {
        super(pRegisterReceiver, pThreadPoolSize, pPendingQueueSize);
        setTileSource(pTileSource);

        mAssets = pAssets;
    }
    // ===========================================================
    // Getter & Setter
    // ===========================================================

    // ===========================================================
    // Methods from SuperClass/Interfaces
    // ===========================================================

    @Override
    public boolean getUsesDataConnection() {
        return false;
    }

    @Override
    protected String getName() {
        return "Assets Cache Provider";
    }

    @Override
    protected String getThreadGroupName() {
        return "assets";
    }

    @Override
    public TileLoader getTileLoader() {
        return new TileLoader(mAssets);
    }

    @Override
    public int getMinimumZoomLevel() {
        ITileSource tileSource = mTileSource.get();
        return tileSource != null ? tileSource.getMinimumZoomLevel() : OpenStreetMapTileProviderConstants.MINIMUM_ZOOMLEVEL;
    }

    @Override
    public int getMaximumZoomLevel() {
        ITileSource tileSource = mTileSource.get();
        return tileSource != null ? tileSource.getMaximumZoomLevel()
                : com.talkweb.osmharmony.util.TileSystem.getMaximumZoomLevel();
    }

    @Override
    public void setTileSource(final ITileSource pTileSource) {
        mTileSource.set(pTileSource);
    }

    // ===========================================================
    // Inner and Anonymous Classes
    // ===========================================================

    protected class TileLoader extends MapTileModuleProviderBase.TileLoader {
        private ResourceManager mAssets = null;

        public TileLoader(ResourceManager pAssets) {
            mAssets = pAssets;
        }

        @Override
        public Element loadTile(final long pMapTileIndex) throws CantContinueException {
            ITileSource tileSource = mTileSource.get();
            if (tileSource == null) {
                return null;
            }

            try {
                InputStream is = mAssets.getRawFileEntry(tileSource.getTileRelativeFilenameString(pMapTileIndex)).openRawFile();
                final Element element = tileSource.getDrawable(is);
                if (element != null) {
                    //https://github.com/osmdroid/osmdroid/issues/272 why was this set to expired?
                    //ExpirableBitmapDrawable.setDrawableExpired(element);
                }
                return element;
            } catch (IOException e) {
            } catch (final LowMemoryException e) {
                throw new CantContinueException(e);
            }

            // If we get here then there is no file in the file cache
            return null;
        }
    }
}
